home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / dbdoc.zip / MDXDOC.C < prev    next >
C/C++ Source or Header  |  1992-03-06  |  14KB  |  362 lines

  1. /*    Somerset Data Systems, Inc.  (908) 766-5845                           */
  2. /*    Version 1.3     March 5, 1992                                         */
  3. /*    Programmer:     Jay Parsons                                           */
  4.  
  5. /****************************************************************************/
  6. /*                          mdxdoc.c                                        */
  7. /*                                                                          */
  8. /*  Program to analyze contents of an .mdx file.               */
  9. /*                                                                          */
  10. /****************************************************************************/
  11.  
  12. #include <ctype.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <mem.h>
  17.  
  18. /****************************************************************************/
  19. /*                          definitions                                     */
  20. /****************************************************************************/
  21.  
  22. /****                      ****  values  ****                            ****/
  23. #define FALSE          0
  24. #define TRUE           1
  25.  
  26. #define MDXTYPE        2            /* type code for .mdx file              */
  27. #define PRODTYPE       1            /* type code for production .mdx        */
  28. #define MAINHEADLEN   48            /* sizeof main header                   */
  29.  
  30. #define PAGELEN      512            /* length in bytes of a page            */
  31. #define TAGARRAYPAGE   1            /* offset of tag array in file in pages */
  32. #define DESCRIPLEN    32            /* sizeof tag array descriptor          */
  33.  
  34. #define INDHEADLEN   129            /* sizeof index header actually used    */
  35.  
  36. #define CHARACTER     'C'           /* character-type key expression        */
  37. #define DATE          'D'           /* date-type key expression             */
  38. #define NUMERIC       'N'           /* numeric-type key expression          */
  39.  
  40. #define DESCENDING  0x08            /* index is descending                  */
  41. #define TAGFIELD    0x10            /* shows tag is a field in file         */
  42. #define UNIQUE      0x40            /* index excludes duplicate keys        */
  43.  
  44. #define SQLTYPE        1            /* optimized for SQL use                */
  45. #define BLOCKHEADLEN   8            /* header length of index body block    */
  46.  
  47. /****                     ****  data types  ****                         ****/
  48.  
  49. typedef unsigned long ulong;        /* just an abbreviation                 */
  50.  
  51. /*  dBASE date marker in file       */
  52.  
  53. typedef struct
  54. {
  55.     char year;
  56.     char month;
  57.     char day;
  58. } dbfdate;
  59.  
  60. /*  first 48 bytes of an .mdx file   */
  61.  
  62. typedef struct
  63. {
  64.     char filetype;                  /* error if not MDXTYPE                 */
  65.     dbfdate lastreindex;            /* last reindex date                    */
  66.     char dbfname[16];               /* root name of associated .dbf         */
  67.     int blocksize;                  /* SET BLOCKSIZE value, minimum = 2     */
  68.     int blockbytes;                 /* block size in bytes                  */
  69.     char production;                /* 1 if production .mdx, else 0         */
  70.     char resrvd1[3];
  71.     int indexes;                    /* number of indexes in the file        */
  72.     char resrvd2[2];
  73.     ulong endfilepage;              /* page number of end of file           */
  74.     ulong nextfreepage;             /* page number of next free block       */
  75.     ulong freepages;                /* pages in next free block             */
  76.     dbfdate created;                /* file creation date                   */
  77.     char resrvd3[1];
  78. } mdxheader;
  79.  
  80. /*  descriptor of a tag         */
  81.  
  82. typedef struct
  83. {
  84.     long indheaderpage;             /*  page number of index header         */
  85.     char tagname[11];               /*  the tag name, in caps, null-filled  */
  86.     char tagfieldflag;              /*  10 if tag is a field, else 0        */
  87.     unsigned char counters[3];      /*  mysterious usage counters           */
  88.     unsigned char useless;          /*  always 02                           */
  89.     unsigned char keytype;          /*  C, D, or N for key type             */
  90.     char rsrvd[12];
  91. } descriptor;
  92.  
  93. /*  header of an index          */
  94.  
  95. typedef struct
  96. {
  97.     ulong rootpage;                 /* page number of index root            */
  98.     ulong pagesused;                /* pages used by the index              */
  99.     int              : 3;
  100.     int         desc : 1;           /* 1 if DESCENDING, or 0                */
  101.     int     fieldtag : 1;           /* 1 if tag is a field, or 0            */
  102.     int              : 1;
  103.     int         uniq : 1;           /* 1 if index is UNIQUE, or 0           */
  104.     int              : 1;
  105.     unsigned char keytype;          /* C, D or N for key type               */
  106.     unsigned char sql;              /* 1 if optimized for SQL, or 0         */
  107.     char resrvd3;
  108.     unsigned keylength;             /* length of key in bytes               */
  109.     ulong maxnodes;                 /* maximum nodes in a block             */
  110.     unsigned ireclen;               /* length of an index record in bytes   */
  111.     unsigned changes;               /* change counter for optimization      */
  112.     char resrvd4;
  113.     char uniqueflag;                /* 40h if UNIQUE, or 0                  */
  114.     char keyexpression[101];        /* the key expression itself            */
  115. } indexheader;
  116.  
  117. /*  an index node               */
  118.  
  119. typedef struct
  120. {
  121.     ulong nodepointer;              /* record number of this key value in   */
  122.                                     /* .dbf if the node is in a block of    */
  123.                                     /* nodes of the lowest level.  Other-   */
  124.                                     /* wise, page number of block of next   */
  125.                                     /* lower level to search.               */
  126.  
  127.     char key[];                     /* the key value, filled with garbage   */
  128.                                                 /* to a number of bytes divisible by 4  */
  129. } node;
  130.  
  131. /*  an index block              */
  132.  
  133. typedef struct
  134. {
  135.     ulong nodesinblock;             /* nodes in use in this block of index */
  136.     ulong prevpage;                 /* page of logically previous block    */
  137.                                     /* will be 0 if this block is first at */
  138.                                     /* this level                          */
  139.  
  140.     node nodes[];                   /* array of nodes                      */
  141.     ulong lowflag;                  /* 0 if this block is lowest level, or */
  142.                                     /* same as prevpage                    */
  143.  
  144.     char garbage[];                 /* to fill the block                   */
  145. } indexblock;
  146.  
  147. /*     globals          */
  148.  
  149. extern char message[], tempbuff[], file_name[];
  150.  
  151. /****              ****  function prototypes  ****                       ****/
  152.  
  153. int mdxdoc ( char *filespec );
  154.  
  155. FILE *mdxopen ( char *filespec, mdxheader *buf );
  156.  
  157. /****************************************************************************/
  158. /*                              mdxdoc                                      */
  159. /*  Principal routine of this module.  Reads and prints a description of    */
  160. /*  the .mdx file identified by the filespec passed.                        */
  161. /*  Parameters:                                                             */
  162. /*      char *filespec  -- pointer to specification of the .mdx file        */
  163. /*  Returns:                                                                */
  164. /*      0 if successful, 1 if any error occurs.                             */
  165. /*  Side effects:                                                           */
  166. /*      stores message, calls Printit.                                      */
  167. /*                                                                          */
  168. /****************************************************************************/
  169.  
  170. int mdxdoc ( char *filespec )
  171. {
  172.     FILE *mdxfile;
  173.     mdxheader mainhead;
  174.     descriptor tag;
  175.     indexheader indexhead;
  176.     char tagtype[11];
  177.     int i, nexttag;
  178.  
  179. /* open file, check for .mdx type, print names */
  180.  
  181.     if ( ( mdxfile = mdxopen( filespec, &mainhead ) ) == NULL )
  182.     {
  183.         sprintf( message, "Can't open file %s ", filespec );
  184.         return 1;
  185.     }
  186.     sprintf( message, "\n%s indexes the file %s ", filespec, mainhead.dbfname );
  187.  
  188. /* print production or not from byte 24    */
  189.  
  190.     if ( mainhead.production == PRODTYPE )
  191.         strcat( message, "as its " );
  192.     else
  193.         strcat( message, "as a non-");
  194.  
  195.     strcat( message, "production .mdx file.\n" );
  196.     printit( 0 );
  197.  
  198. /* print dates from bytes 02-04 and 45-47  */
  199.  
  200.     sprintf( message, "It was originally created %02d/%02d/%02d",
  201.         (int) mainhead.created.month,
  202.         (int) mainhead.created.day,
  203.         (int) mainhead.created.year );
  204.  
  205.     if ( mainhead.created.year == mainhead.lastreindex.year &&
  206.           mainhead.created.month == mainhead.lastreindex.month &&
  207.           mainhead.created.day == mainhead.lastreindex.day )
  208.         strcat( message, " and has not been reindexed since that date." );
  209.     else
  210.         sprintf( tempbuff, " and last reindexed %02d/%02d/%02d.",
  211.             (int) mainhead.lastreindex.month,
  212.             (int) mainhead.lastreindex.day,
  213.             (int) mainhead.lastreindex.year );
  214.     strcat( message, tempbuff );
  215.     printit( 0 );
  216.  
  217. /* print size and indexes from bytes 21-24 and 27-28   */
  218.  
  219.     sprintf( message, "Its blocks are BLOCKSIZE %d, %d bytes long.\n",
  220.         mainhead.blocksize, mainhead.blockbytes );
  221.     printit( 0 );
  222.  
  223.     sprintf( message, "It contains %d index", mainhead.indexes );
  224.         if ( mainhead.indexes > 1 )
  225.             strcat( message, "es" );
  226.     strcat( message, ":\n" );
  227.     printit( 0 );
  228.  
  229. /*  point to first tag descriptor and loop through all  */
  230.  
  231.     nexttag = TAGARRAYPAGE * PAGELEN + DESCRIPLEN;
  232.  
  233.     for ( i = 1; i <= mainhead.indexes; i++, nexttag += DESCRIPLEN )
  234.     {
  235.  
  236. /*  read and print descriptor information   */
  237.  
  238.         if ( fseek( mdxfile, nexttag, SEEK_SET ) != 0 )
  239.         {
  240.             fclose( mdxfile );
  241.             strcpy( message, "Can't reach tag descriptor" );
  242.             return 1;
  243.         }
  244.         if ( fread( &tag, DESCRIPLEN, 1, mdxfile ) != 1 )
  245.         {
  246.             fclose( mdxfile );
  247.             strcpy( message, "Can't read tag descriptor" );
  248.             return 1;
  249.         }
  250.         if ( tag.tagfieldflag == TAGFIELD )
  251.         {
  252.             sprintf( message, "%-10s tags a ", tag.tagname );
  253.             strcpy( tagtype, "field" );
  254.         }
  255.         else
  256.         {
  257.             sprintf( message, "%-10s tags an ", tag.tagname );
  258.             strcpy( tagtype, "expression" );
  259.         }
  260.         sprintf( tempbuff, "%s of type %c", tagtype, tag.keytype );
  261.         strcat( message, tempbuff );
  262.         printit( 0 );
  263.  
  264. /*  and index header information            */
  265.  
  266.         if ( fseek( mdxfile, tag.indheaderpage * PAGELEN, SEEK_SET ) != 0 )
  267.         {
  268.             fclose( mdxfile );
  269.             strcpy( message, "Can't reach index header" );
  270.                 return 1;
  271.         }
  272.         if ( fread( &indexhead, INDHEADLEN, 1, mdxfile ) != 1 )
  273.         {
  274.             fclose( mdxfile );
  275.             strcpy( message, "Can't read index header" );
  276.             return 1;
  277.         }
  278.  
  279.         if ( indexhead.uniq || indexhead.desc || indexhead.sql )
  280.         {
  281.             strcpy( message, "The index is " );
  282.  
  283.             if ( indexhead.uniq )
  284.             {
  285.                 strcat( message, "UNIQUE" );
  286.                 if ( indexhead.desc && indexhead.sql )
  287.                     strcat( message, ", DESCENDING and SQL-optimized" );
  288.                 else
  289.                 {
  290.                     if( indexhead.desc )
  291.                         strcat( message, " and DESCENDING" );
  292.                     if( indexhead.sql  )
  293.                         strcat( message, " and SQL-optimized" );
  294.                 }
  295.             }
  296.             else
  297.                 if ( indexhead.desc && indexhead.sql )
  298.                     strcat( message, "DESCENDING and SQL-optimized" );
  299.                 else
  300.                     if( indexhead.desc )
  301.                         strcat( message, "DESCENDING" );
  302.                     else
  303.                         strcat( message, "SQL-optimized" );
  304.             strcat( message, "." );
  305.             printit( 0 );
  306.         }
  307.         sprintf( message, "    Keys are %d byte", indexhead.keylength );
  308.         if( indexhead.keylength > 1 )
  309.             strcat( message, "s" );
  310.         sprintf( tempbuff, " long and the key %s is: %s",
  311.         tagtype, indexhead.keyexpression );
  312.         strcat( message, tempbuff );
  313.         printit( 0 );
  314.     }
  315.     fclose( mdxfile );
  316.     return 0;
  317. }
  318.  
  319. /****************************************************************************/
  320. /*                              mdxopen                                     */
  321. /*      Routine to open .mdx file.                                          */
  322. /*  Parameters:                                                             */
  323. /*      char *filespec  -- pointer to spec of file to open                  */
  324. /*      mdxheader *buf  -- pointer to mdxheader structure                   */
  325. /*  Returns:                                                                */
  326. /*      Pointer to C file control structure (to NULL if error)              */
  327. /*  Side effects:                                                           */
  328. /*      Opens file and moves pointer to byte 48; fills buffer at buf with   */
  329. /*  first 48 bytes of file.  Closes file on error.                          */
  330. /****************************************************************************/
  331.  
  332. FILE *mdxopen( char *filespec, mdxheader *buf )
  333.  
  334. {
  335.     FILE *file;
  336.  
  337.     if ( ( file = fopen( filespec, "rb" ) ) == NULL )
  338.     {
  339.         sprintf( message, "Can't open file %s", filespec );
  340.         return NULL;
  341.     }
  342.  
  343.     /* read the first 48 bytes into buffer      */
  344.     if ( fread( buf, MAINHEADLEN, 1, file ) != 1 )
  345.     {
  346.         fclose( file );
  347.         strcpy( message, "Can't read .MDX header bytes" );
  348.         return NULL;
  349.     }
  350.  
  351. /* check first byte to be sure .mdx type                                    */
  352.  
  353.     if ( buf->filetype != MDXTYPE )
  354.     {
  355.         fclose( file );
  356.         strcpy( message, "Not a valid .MDX file" );
  357.         return NULL;
  358.     }
  359.     return file;
  360. }
  361.  
  362.